﻿using Microsoft.Extensions.Logging;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace WpfApp.MesServices
{
    internal class InBoundMesService
    {
        private readonly ILogger<InBoundMesService> _logger;
        private static readonly HttpClient _httpClient = new HttpClient();
        private const string SoapNamespace = "http://schemas.xmlsoap.org/soap/envelope/";
        private const string MifNamespace = "http://miFirstOperationForsfc.ws.atlmes.com/";
        private const string EndUrl = "/atlmeswebservice/MiFirstOperationForsfcServiceService?wsdl";

        public InBoundMesService(ILogger<InBoundMesService> logger)
        {
            _logger = logger;
        }

        public async Task<StartResponseMessageDto> PostAsync(StartRequestMessageDto model)
        {
            if (string.IsNullOrWhiteSpace(model.Url))
            {
                return CreateErrorResponse("MesApi 地址为空，请点击主页面'配置按钮'，进入配置页面，在'API 地址'一栏输入 API 地址。");
            }

            try
            {
                var url = model.Url?.TrimEnd('/') + EndUrl;
                _logger.LogInformation("本次分类调用API为：{Url}", url);

                var response = await SendSoapRequestAsync(model);

                if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
                {
                    return CreateErrorResponse($"MES 配置用户名或密码不正确，不能认证极片分类！");
                }
                else if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
                {
                    return CreateErrorResponse($"MES API 地址[{url}]不能访问！");
                }
                else if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
                {
                    return CreateErrorResponse($"MES 内部服务器错误，请检查条码或者 MES 配置是否正确！");
                }
                else if (response.StatusCode != System.Net.HttpStatusCode.OK)
                {
                    _logger.LogInformation("接收SOAP响应报文：{ResponseContent}", await response.Content.ReadAsStringAsync());
                    return CreateErrorResponse($"MES API 地址[{url}]访问失败，错误码 {response.StatusCode.ToString()} ！");
                }

                return ParseSoapResponse(await response.Content.ReadAsStringAsync(), model.Sfc ?? string.Empty);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "MES服务调用失败，SFC: {Sfc}", model.Sfc);
                return CreateErrorResponse($"SFC {model.Sfc} 分类失败，请查看极片自动分类软件 MES 日志！");
            }
        }

        private async Task<HttpResponseMessage> SendSoapRequestAsync(StartRequestMessageDto model)
        {
            string soapBody = BuildSoapRequestBody(model);
            _logger.LogInformation("发送SOAP请求报文：{SoapBody}", soapBody);

            var content = new StringContent(soapBody, Encoding.UTF8, "text/xml");
            string authToken = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{model.UserName}:{model.Password}"));

            var url = model.Url?.TrimEnd('/') + EndUrl;
            using (var request = new HttpRequestMessage(HttpMethod.Post, url))
            {
                request.Content = content;
                request.Headers.Authorization = new AuthenticationHeaderValue("Basic", authToken);

                return await _httpClient.SendAsync(request);
            }
        }

        private string BuildSoapRequestBody(StartRequestMessageDto model)
        {
            return $@"<soapenv:Envelope xmlns:soapenv=""{SoapNamespace}"" xmlns:mif=""{MifNamespace}"">
   <soapenv:Header/>
   <soapenv:Body>
      <mif:miFirstOperationForsfc>
         <MiFirstOperationForsfcRequest>
            <site>{EscapeXml(model.Site)}</site>
            <resource>{EscapeXml(model.Resource)}</resource>
            <modeProcessSfc>{EscapeXml(model.ModeProcessSfc)}</modeProcessSfc>
            <operation>{EscapeXml(model.Operation)}</operation>
            <activity>{EscapeXml(model.Activity)}</activity>
            <operationRevision>{EscapeXml(model.OperationRevision)}</operationRevision>
            <user>{EscapeXml(model.User)}</user>
            <sfc>{EscapeXml(model.Sfc)}</sfc>
            <processLot>{EscapeXml(model.ProcessLot)}</processLot>
         </MiFirstOperationForsfcRequest>
      </mif:miFirstOperationForsfc>
   </soapenv:Body>
</soapenv:Envelope>";
        }

        private StartResponseMessageDto ParseSoapResponse(string responseContent, string sfc)
        {
            _logger.LogInformation("接收SOAP响应报文：{ResponseContent}", responseContent);

            var xmlDocument = new XmlDocument();
            xmlDocument.LoadXml(responseContent);

            var namespaceManager = new XmlNamespaceManager(xmlDocument.NameTable);
            namespaceManager.AddNamespace("soap", SoapNamespace);
            namespaceManager.AddNamespace("mif", MifNamespace);

            var codeNode = xmlDocument.SelectSingleNode("//code", namespaceManager);
            var messageNode = xmlDocument.SelectSingleNode("//message", namespaceManager);

            if (codeNode == null || messageNode == null)
            {
                throw new InvalidOperationException("非标准 MES 响应报文，缺少 code 或 message 节点。");
            }

            if (codeNode.InnerText == "0")
            {
                return HandleSuccessResponse(messageNode.InnerText, sfc);
            }
            else
            {
                return HandleErrorResponse(codeNode.InnerText, messageNode.InnerText, sfc);
            }
        }

        private StartResponseMessageDto HandleSuccessResponse(string message, string sfc)
        {
            if (string.IsNullOrWhiteSpace(message) || !ContainsDigits(message))
            {
                return CreateErrorResponse($"SFC {sfc} 分类失败，MES不支持极片分类。");
            }

            return new StartResponseMessageDto
            {
                Success = true,
                Message = message
            };
        }

        private StartResponseMessageDto HandleErrorResponse(string code, string message, string sfc)
        {
            return CreateErrorResponse($"SFC {sfc} 分类失败，错误码：{code}，错误信息：{message}");
        }

        private StartResponseMessageDto CreateErrorResponse(string message)
        {
            return new StartResponseMessageDto
            {
                Success = false,
                Message = message
            };
        }

        private bool ContainsDigits(string input)
        {
            foreach (char c in input)
            {
                if (char.IsDigit(c))
                {
                    return true;
                }
            }
            return false;
        }

        private string EscapeXml(string? input)
        {
            if (string.IsNullOrEmpty(input))
                return string.Empty;

            return input
                .Replace("&", "&amp;")
                .Replace("<", "&lt;")
                .Replace(">", "&gt;")
                .Replace("\"", "&quot;")
                .Replace("'", "&apos;");
        }
    }
}